package web;

import domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import db.ActivityRepository;
import db.AnnouncementRepository;
import db.ClubRepository;
import db.MembershipApplicationRepository;
import db.UserRepository;

import javax.servlet.http.HttpSession;

import java.awt.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

/**
 * 用户控制类
 *
 * @author zdc
 * @author Zhelang
 */
@Controller
@SessionAttributes({ "user" })
@RequestMapping("/user")
public class UserController {

    private static final RequestMethod[] PUT = null;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private ClubRepository clubRepository;
    @Autowired
    private ActivityRepository activityRepository;
    @Autowired
    private AnnouncementRepository announcementRepository;
    @Autowired
    private MembershipApplicationRepository membershipApplicationRepository;

    /**
     * 展示用户界面。
     *
     * 该方法从会话中获取当前用户信息，并查询用户加入的所有社团和参与的活动。
     * 将这些信息添加到模型中，用于在视图上展示用户的社团数量和活动数量。
     *
     * @param model Model 对象，用于向视图添加属性。
     * @return 用户界面的视图名称 "userView"。
     */
    @RequestMapping(method = GET)
    public String showUserView(@CookieValue(value = "userId", defaultValue = "-1") int userId, Model model) {

        if(userId != -1) {  // 从Cookie获取当前登录的用户id
            // 用户首页展示用户加入的所有社团
            List<Club> clubs = clubRepository.findByUserId(userId);
            model.addAttribute("clubs", clubs);
            model.addAttribute("clubCount", clubs.size());  // 用户加入的社团个数

            // 用户首页展示用户参加的所有活动
            List<Activity> activities = activityRepository.findActivityByUserId(userId);
            model.addAttribute("activities", activities);
            model.addAttribute("activityCount", activities.size());  // 用户参与的活动个数
        } else {
            return "redirect:/";    // 没有登录用户则返回首页
        }

        return "userView";
    }

    /**
     * 展示用户的个人资料页面。
     *
     * 如果用户已经登录（即 user 对象不为 null），则将用户信息添加到模型中并返回个人资料视图。
     * 如果用户未登录，则重定向到网站的首页。
     *
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性，包括用户信息。
     * @return 如果用户已登录，返回个人资料页面的视图名称 "profile"；
     *         如果用户未登录，返回重定向到网站首页的路径 "redirect:/"。
     */
    @RequestMapping(value = "/profile", method = GET)
    public String showUserProfile(HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        if (user != null) {
            model.addAttribute(user);
            return "profile";
        } else {
            return "redirect:/";
        }
    }

    /**
     * 用户提交更新个人信息。
     *
     * 该方法接收用户通过表单提交的个人信息更新，包括昵称、电话号码、电子邮件、性别和学院。
     * 如果某些字段没有提供值，则会使用默认值。更新成功后，用户信息将保存到数据库，
     * 并返回个人资料视图。
     *
     * @param nickname 用户提供的新昵称，默认值为空字符串。
     * @param telephone 用户提供的新电话号码，默认值为空字符串。
     * @param email 用户提供的新电子邮件，默认值为空字符串。
     * @param gender 用户提供的性别，true 或 false，默认值为 true。
     * @param college 用户提供的学院名称，默认值为 "software"。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 更新成功后，返回个人资料页面的视图名称 "profile"。
     */
    @RequestMapping(value = "/updateUserInfo", method = POST)
    public String updateUserInfo(@RequestParam(value = "nickname", defaultValue = "") String nickname,
                                @RequestParam(value = "telephone", defaultValue = "") String telephone,
                                @RequestParam(value = "email", defaultValue = "") String email,
                                @RequestParam(value = "gender", defaultValue = "true") boolean gender,
                                @RequestParam(value = "college", defaultValue = "software") String college,
                                 HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        user.setNickname(nickname);
        user.setTelephone(telephone);
        user.setEmail(email);
        user.setGender(gender);
        user.setCollege(college);
        userRepository.update(user);
        return "profile";
    }

    /**
     * 获取社团列表并根据提供的名称进行过滤。
     *
     * 此方法获取所有社团的列表，如果提供了社团名称，则会过滤出包含该名称的社团。
     * 同时，该方法还会检查当前用户加入的社团，并为每个社团设定加入状态：
     * 0 表示审核中，1 表示已加入，-1 表示未加入。
     * 最后，将这些信息添加到模型中，供视图使用。
     *
     * @param pageNo 分页参数，表示当前请求的页码，默认值为 1。
     * @param clubName 用户可以通过该参数过滤社团名称，默认值为 "null"，表示不过滤。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回社团列表页面的视图名称 "clubs"。
     */
    @RequestMapping(value = "/clubs",method = GET)
    public String clubList(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
                           @RequestParam(value = "clubName", defaultValue = "null") String clubName,
                           HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        pageNo = pageNo < 1 ? 1 : pageNo;
        List<Club> temp_clubs = clubRepository.findAll();
        List<Club> clubs = temp_clubs;
        // 添加社团负责人
        for(int i=0;i<temp_clubs.size();i++) {
            clubs.set(i, clubRepository.findOne(temp_clubs.get(i).getClubID()));
        }

        List<Club> clubList = clubs;
        if(!clubName.equals("null")) {
            clubList = clubs.stream()
                    .filter(club -> club.getClubName().contains(clubName))
                    .collect(Collectors.toList());
        }

        // 获取我加入的社团列表
        List<Club> myClubList = clubRepository.findByUserId(user.getUserID());

        // 判断用户加入的社团，记录状态： 0 审核中 | 1 已加入 | -1 未加入
        int[] joinStatus = new int[clubList.size()];
        for(int i = 0; i < clubList.size(); i++) {
            if(myClubList.contains(clubList.get(i))){
                joinStatus[i] = 1;
            } else {
                joinStatus[i] = -1;
            }
        }
        model.addAttribute("joinStatus", joinStatus);
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("clubList", clubList);
        model.addAttribute("totalPage", (clubList.size() + 9) / 10);
        return "clubs";
    }


    /**
     * 获取用户已加入的社团列表，并可以根据社团名称进行过滤。
     *
     * 此方法首先查询用户加入的所有社团，然后如果提供了社团名称，将进一步过滤这些社团。
     * 由于这个列表只包含用户加入的社团，因此所有的社团加入状态都设置为 1（已加入）。
     * 分页参数用于确定要返回哪一页的社团。
     * 最后，将社团列表和相关数据添加到模型中，供视图使用。
     *
     * @param pageNo 分页参数，表示当前请求的页码，默认值为 1。如果页码小于 1，将被重置为 1。
     * @param clubName 用户可以通过该参数来过滤社团名称，默认值为空字符串，表示不过滤。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回社团列表页面的视图名称 "myClubs"。
     */
    @RequestMapping(value = "/myClubs",method = GET)
    public String myClubList(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
                           @RequestParam(value = "clubName", defaultValue = "") String clubName,
                             HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        // 确保页码有效
        pageNo = pageNo < 1 ? 1 : pageNo;
        List<Club> temp_clubs = clubRepository.findByUserId(user.getUserID());
        List<Club> clubs = temp_clubs;
        // 添加社团负责人
        for(int i=0;i<temp_clubs.size();i++) {
            clubs.set(i, clubRepository.findOne(temp_clubs.get(i).getClubID()));
        }

        // 过滤社团列表，只保留当前登录的用户对象的社团
        List<Club> clubList = clubs.stream()
                .filter(club -> club.getClubName().contains(clubName))
                .collect(Collectors.toList());

        int[] joinStatus = new int[clubList.size()];
        // 所有社团状态设置为已加入
        for(int i = 0; i < clubList.size(); ++i) joinStatus[i] = 1;
        model.addAttribute("joinStatus", joinStatus);

        model.addAttribute("currentPage", pageNo);
        model.addAttribute("clubList", clubList);
        model.addAttribute("totalPage", (clubList.size() + 9) / 10);
        return "clubs";
    }

    /**
     * 处理用户请求加入社团的方法。
     *
     * 当一个用户尝试加入一个社团时，此方法会创建一个新的社团加入申请，并将其保存到仓库中。
     * 申请初始状态设置为待审批（0）。如果申请成功保存到仓库，模型中会添加一个成功的结果标识；
     * 如果保存失败，模型中会添加一个失败的结果标识。这些信息将被视图用来显示相应的加入结果。
     *
     * @param clubID 社团ID，用户请求加入的社团的唯一标识符。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回社团列表页面的视图名称 "clubs"，包含加入结果。
     */
    @RequestMapping(value = "/joinClub", method = GET)
    public String joinClub(@RequestParam(value = "clubId") int clubID, HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        // 创建一个新的申请
        int status = 0; // 0 待审批状态
        String description = "Join club request"; // 申请描述
        MembershipApplication membershipApplication = new MembershipApplication(new Date(), user, status, description, 0, clubID);
        membershipApplication = membershipApplicationRepository.save(membershipApplication);
        if (membershipApplication == null) {
            model.addAttribute("joinResult", -1);
        } else {
            model.addAttribute("joinResult", 1);
        }
        return "clubs";
    }

    /**
     * 处理用户请求退出社团的方法。
     *
     * 该方法调用社团仓库的 `quitClub` 方法，尝试让用户退出指定的社团。
     * 如果用户成功退出社团，`isQuit` 将为 true；如果操作失败，`isQuit` 将为 false。
     * 方法将重定向用户到社团列表页面，并可能显示相应的退出结果消息。
     *
     * @param clubId 社团ID，用户请求退出的社团的唯一标识符。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。本例中未使用。
     * @return 重定向到用户社团列表页面的路径。
     */
    @RequestMapping(value = "/quitClub", method = GET)
    public String quitClub(@RequestParam(value = "clubId") int clubId, HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        boolean isQuit = clubRepository.quitClub(user.getUserID(), clubId);
        model.addAttribute("clubName", "null");

        return "redirect:/user/clubs";
    }

    /**
     * 获取并展示活动列表的方法，可选地根据活动名称进行筛选。
     *
     * 此方法首先确保提供的页码不小于1。然后，它调用活动仓库的 `findAll` 方法以获取所有活动。
     * 如果提供了活动名称作为筛选条件，则通过活动名称来过滤这些活动。最后，将活动列表、当前页码
     * 以及总页数添加到模型中，这些信息将用于在视图中显示。
     *
     * @param pageNo 请求的页码，默认值为1。如果小于1，会被重置为1。
     * @param activityName 活动名称的筛选条件，默认为空字符串，表示不进行筛选。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回活动列表页面的视图名称 "activities"。
     */
    @RequestMapping(value = "/activities",method = GET)
    public String activityList(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
                               @RequestParam(value = "activityName", defaultValue = "") String activityName,
                               HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        // 确保页码有效
        pageNo = pageNo < 1 ? 1 : pageNo;

        // 查找所有活动
        List<Activity> activities = activityRepository.findAll();
        List<Activity> activityList = activities;
        if(!activityName.isEmpty()) {
            // 过滤活动列表，只留下匹配搜索活动名的活动
            activityList = activities.stream()
                    .filter(activity -> activity.getActivityName().contains(activityName))
                    .collect(Collectors.toList());
        }

        model.addAttribute("currentPage", pageNo);
        model.addAttribute("activityList", activityList);
        model.addAttribute("totalPage", (activityList.size() + 9) / 10);
        return "activities";
    }

    /**
     * 获取并展示当前用户参与的所有活动列表的方法，可选地根据活动名称进行筛选。
     *
     * 此方法首先确保提供的页码不小于1。然后，它调用活动仓库的 `findActivityByUserId` 方法，
     * 使用当前用户的ID来获取用户参与的所有活动。如果提供了活动名称作为筛选条件，则通过活动名称
     * 来过滤这些活动。最后，将活动列表、当前页码以及总页数添加到模型中，这些信息将用于在视图中显示。
     *
     * @param pageNo 请求的页码，默认值为1。如果小于1，会被重置为1。
     * @param activityName 活动名称的筛选条件，默认为空字符串，表示不进行筛选。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回用户的活动列表页面的视图名称 "activities"。
     */
    @RequestMapping(value = "/myActivities",method = GET)
    public String myActivityList(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
                                 @RequestParam(value = "activityName", defaultValue = "") String activityName,
                                 HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        pageNo = pageNo < 1 ? 1 : pageNo;
        List<Activity> activities = activityRepository.findActivityByUserId(user.getUserID());
        List<Activity> activityList = activities.stream()
                .filter(activity -> activity.getActivityName().contains(activityName))
                .collect(Collectors.toList());
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("activityList", activities);
        model.addAttribute("totalPage", (activityList.size() + 9) / 10);
        return "activities";
    }

    /**
     * 根据提供的活动ID获取特定活动的详细信息。
     *
     * 此方法首先通过活动仓库的 `findOne` 方法尝试获取对应的活动。如果找到了该活动，
     * 则将其添加到模型中，并返回活动详情页面的视图名称。如果没有找到活动，则返回
     * 到活动列表页面。
     *
     * @param activityID 活动的唯一标识符。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 如果找到活动，返回活动详情页面的视图名称 "activityInfo"；如果未找到，
     * 返回活动列表页面的视图名称 "activities"。
     */
    @RequestMapping(value = "/activityInfo",method = GET)
    public String findByActivityName(@RequestParam(value = "activityID") int activityID,
                                     HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        Activity activity = activityRepository.findOne(activityID);
        if(activity != null) {
            model.addAttribute("activity", activity);
            return "activityInfo";

        }
        return "activities";
    }

    /**
     * 根据提供的社团ID获取特定社团的详细信息。
     *
     * 该方法通过社团仓库的 `findOne` 方法获取对应的社团，并将其添加到模型中。
     * 然后返回社团详情页面的视图名称。
     *
     * @param clubId 社团的唯一标识符。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 社团详情页面的视图名称 "clubInfo"。
     */
    @RequestMapping(value = "/clubInfo",method = GET)
    public String findByClubName(@RequestParam(value = "clubId") int clubId, HttpSession session, Model model) {

        Club club = clubRepository.findOne(clubId);
        model.addAttribute("club", club);
        return "clubInfo";
    }

    /**
     * 获取并展示当前用户收到的所有公告信息。分页显示。
     *
     * 此方法首先确保提供的页码不小于1。然后，根据当前用户ID查询所属的社团，
     * 并收集这些社团发布的所有公告。最后，将公告列表、当前页码以及总页数添加到模型中，
     * 供前端视图展示。
     *
     * @param pageNo 请求的页码，默认值为1。如果请求的页码小于1，会被重置为1。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回公告信息页面的视图名称 "announcements"。
     */
    @RequestMapping(value = "/announcements", method = GET)
    public String userAnnouncements(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo, HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        pageNo = pageNo < 1 ? 1 : pageNo;

        List<Club> clubs = clubRepository.findByUserId(user.getUserID());
        List<Announcement> announcements = new ArrayList<>();
        for(Club club : clubs) {
            List<Announcement> announcementList = announcementRepository.findAnnouncementsByClub(club);
            announcements.addAll(announcementList);
        }
        model.addAttribute("announcements", announcements);
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPage", (announcements.size() + 9) / 10);
        return "announcements";
    }

    /**
     * 获取并展示当前用户所有的申请信息。分页显示。
     *
     * 此方法首先确保提供的页码不小于1。接着，根据当前用户ID查询所属的社团，
     * 并收集这些社团相关的所有申请。最后，将申请列表、当前页码以及总页数添加到模型中，
     * 供前端视图展示。
     *
     * 注意：当前代码示例中未展示如何获取申请信息列表，可能需要从申请仓库中
     * 调用相应方法来填充 `applications` 列表。
     *
     * @param pageNo 请求的页码，默认值为1。如果请求的页码小于1，会被重置为1。
     * @param session 当前用户会话信息。
     * @param model Model 对象，用于向视图添加属性。
     * @return 返回用户申请页面的视图名称 "applications"。
     */
    @RequestMapping(value = "/applications", method = GET)
    public String applications(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo, HttpSession session, Model model) {
        User user = (User)session.getAttribute("user");  // 获取当前用户

        pageNo = pageNo < 1 ? 1 : pageNo;
        List<Club> clubs = clubRepository.findByUserId(user.getUserID());
        List<Application> applications = new ArrayList<>();

        model.addAttribute("applications", applications);
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPage", (applications.size() + 9) / 10);
        return "applications";
    }

}

